/*
 * Albareth - an action roleplaying game.
 * Copyright (C) 2008 Jens Anuth
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 *   02110-1301, USA.
 * 
 * $Id: Game.java 46 2008-05-15 18:09:39Z jens464 $
*/
package albareth.core;

import java.util.Iterator;
import java.util.List;

import albareth.core.entity.Entity;
import albareth.core.entity.Mobile;
import albareth.core.entity.PlayerCharacter;
import albareth.generator.WorldGenerator;
import frosch.util.Task;
import frosch.util.TaskScheduler;
import frosch.util.glider.Easing;

public class Game implements GameContext, PerceptionDispatcher
{
    public static final String VERSION  = "Preview 1";
    public static final String SUBTITLE = "Slugs and Slimes";

    private static Game _instance = null;
    
    public static final boolean CHEAT_MODE = false;
    public static final int RANGEOFSIGHT = 6;



    private TaskScheduler _taskScheduler;
    
    private World _world;
    
    private PlayerCharacter _player;
    
    
    private long _lastUpdateSystemTime = System.currentTimeMillis();
    
    private boolean _gamePaused = false;
    
    
    
    private Game(World world)
    {
        _world = world;
        _taskScheduler = new TaskScheduler();
    }
    
    private Game()
    {
        //_world = world;
        _taskScheduler = new TaskScheduler();
    }

    public static Game create()
    {
        World world = new WorldGenerator().generateWorld();
        _instance = new Game(world);
        return _instance;
    }
    
    /*
    public static Game create()
    {
        _instance = new Game();
        return _instance;
    }*/

    
    public static GameContext getContext()
    {
        return _instance;
    }
    
    public void setPlayer(PlayerCharacter player)
    {
        _player = player;
    }
    
    public void update(int delta)
    {
        if (_gamePaused || _player.isFlagSet(Mobile.FLAG_DEAD)) {
            return;
        }
       
        _world.update(delta);

        GameMap playerMap = _player.getMap();

        playerMap.update(this);

        List mobilesToUpdate = playerMap.getAllMobiles();
        for (int i = 0; i < mobilesToUpdate.size(); i++)
        {
            Mobile mob = (Mobile)mobilesToUpdate.get(i);
            mob.update();
        }


        _taskScheduler.update(delta);
        
        _lastUpdateSystemTime = System.currentTimeMillis();
        //System.err.println(getPreciseTime());
    }


    
    /*
     * It follows the implementation of GameContext
     */

    public PlayerCharacter getPlayer()
    {
        return _player;
    }

    public void scheduleTask(Task task, long delay)
    {
        scheduleTask(task, delay, 0);
    }

    public void scheduleTask(Task task, long delay, long period)
    {
        _taskScheduler.scheduleTask(task, delay, period);
    }
    
    public TaskScheduler getTaskScheduler()
    {
        return _taskScheduler;
    }
    
    /**
     * Gets the current world time, as the last update time plus
     * time that has passed since the last update.
     */
    public long getPreciseTime()
    {
        return System.currentTimeMillis() - _lastUpdateSystemTime + _world.getAge();
    }
    
    public long getTime()
    {
        return _world.getAge();
    }

    public World getWorld()
    {
        return _world;
    }
    
    public PerceptionDispatcher getPerceptionDispatcher()
    {
        return this;
    }
    
    
    /*
     * It follows a simple PerceptionDispatcher implementation, in which 
     * _only_ the player receives events to visualize them
     * on his frontend, when they happen on the same map.
     */
    
    public void dispatchEffect(Entity emitter, GameEffect effect)
    {
        if (emitter.getMap() == _player.getMap()) {
            _player.getFrontend().playEffect(effect);
        };
    }

    public void dispatchSound(Entity emitter, String soundId)
    {
        if (emitter.getMap() == _player.getMap()) {
            _player.getFrontend().playSound(soundId);
        }
    }

    public void dispatchSpeech(Entity emitter, String text)
    {
        if (emitter.getMap() == _player.getMap()) {
            _player.getFrontend().speech(emitter, text);
        }
    }

    public void dispatchBroadcast(Entity emitter, String message)
    {
        if (emitter.getMap() == _player.getMap()) {
            _player.getFrontend().infoMsg(message);
        }
    }

    public void dispatchOverheadMessage(Entity emitter, String message,
            String color, Easing easing)
    {
        if (emitter.getMap() == _player.getMap()) {
            _player.getFrontend().overheadMsg(emitter, message, color, easing);
        }
    }

    public void setWorld(World world)
    {
        _world = world;
    }




}
